//
//  MKUIPopoverView.m
//  MKUI
//
//  Created by 苏尚进 on 2024/11/13.
//  Copyright © 2024 moon. All rights reserved.
//

#import "MKUIPopoverView.h"
#import "CGGeometry+MKUI.h"
#import "NSArray+MKUI.h"
#import "UIView+MKUI.h"
@interface _MKUIPopoverViewDirectionAreaInfo : NSObject
@property(nonatomic,assign) UIPopoverArrowDirection direction;
@property(nonatomic,assign) CGFloat area;//面积
@property(nonatomic,assign) CGRect rect;//可用区域
@property(nonatomic,readonly) MKCGAxis directionAxis;
- (id)initWithDirection:(UIPopoverArrowDirection)direction rect:(CGRect)rect;
@end
@implementation _MKUIPopoverViewDirectionAreaInfo
- (id)initWithDirection:(UIPopoverArrowDirection)direction rect:(CGRect)rect{
    if(self=[self init]){
        self.direction = direction;
        self.rect = rect;
        self.area = rect.size.width*rect.size.height;
    }
    return self;
}
- (NSComparisonResult)compare:(_MKUIPopoverViewDirectionAreaInfo *)other{
    return [@(self.area) compare:@(other.area)];
}
- (MKCGAxis)directionAxis{
    return self.direction==UIPopoverArrowDirectionUp||self.direction==UIPopoverArrowDirectionDown ? MKCGAxisY :MKCGAxisX;
}
@end

@interface _MKUIPopoverViewTouchOverlayArrayProxyObject : NSObject
@property(nonatomic,weak) __kindof NSObject *view;
@end
@implementation _MKUIPopoverViewTouchOverlayArrayProxyObject
@end
@interface _MKUIPopoverViewTouchOverlay : UIControl
@property(nonatomic,strong) NSArray<UIView *> *passthroughViews;//
@property(nonatomic,strong) NSArray<_MKUIPopoverViewTouchOverlayArrayProxyObject *> *weakPassthroughViews;//
@end
@implementation _MKUIPopoverViewTouchOverlay
#pragma mark - override
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
    BOOL inside = NO;
    BOOL passthrough = NO;
    for (_MKUIPopoverViewTouchOverlayArrayProxyObject *viewValue in self.weakPassthroughViews) {
        UIView *view = viewValue.view;
        if(!view)continue;
        CGPoint transPoint = [self convertPoint:point toView:view];
        if ([view pointInside:transPoint withEvent:event]) {
            //将事件传递给passthroughView中的视图
            passthrough = YES;
            break;
        }
    }
    if(passthrough){
        inside = NO;
    }else{
        inside = [super pointInside:point withEvent:event];
    }
    return inside;
}
- (void)setPassthroughViews:(NSArray<UIView *> *)passthroughViews{
    self.weakPassthroughViews = [passthroughViews mk_map:^id _Nullable(UIView * _Nonnull obj) {
        _MKUIPopoverViewTouchOverlayArrayProxyObject *proxyObj = [[_MKUIPopoverViewTouchOverlayArrayProxyObject alloc] init];
        proxyObj.view = obj;
        return proxyObj;
    }];
}
- (NSArray<UIView *> *)passthroughViews{
    return [self.weakPassthroughViews mk_map:^id _Nullable(_MKUIPopoverViewTouchOverlayArrayProxyObject * _Nonnull obj) {
        return obj.view;
    }];
}
- (void)dealloc{
    
}
@end

@interface MKUIPopoverView()
@property(nonatomic,assign) UIPopoverArrowDirection popoverArrowDirection;//箭头方向
@property(nonatomic,strong) __kindof MKUIPopoverBorderView *borderView;
@property(nonatomic,strong) _MKUIPopoverViewTouchOverlay *touchOverlayView;
@end

@implementation MKUIPopoverView
- (id)init{
    if(self=[super init]){
        self.clipsToBounds = NO;
        self.contentInsets = MKUIEdgeInsetsMakeSameEdge(10);
        self.popoverMargins = MKUIEdgeInsetsMakeSameEdge(10);
        self.permittedArrowDirections = UIPopoverArrowDirectionAny;
        self.arrowSpacing = 5;
        self.arrowHeight = 7;
        self.shouldAutoDismiss = YES;
        
        self.borderView = [self.class createBorderView];
        self.touchOverlayView = [[_MKUIPopoverViewTouchOverlay alloc] init];
        [self.touchOverlayView addTarget:self action:@selector(_onTouchOverlayViewDidTap:) forControlEvents:(UIControlEventTouchUpInside)];
        [self addSubview:self.borderView];
    }
    return self;
}
- (void)dealloc{
    
}
+ (CGRect)arrowPointToRectFrom:(UIView *)pointToView inContainerView:(UIView *)containerView{
    CGRect arrowPointToRect = CGRectApplyAffineTransform(pointToView.mk_frameSafety, pointToView.transform);
    arrowPointToRect = [pointToView.superview convertRect:arrowPointToRect toView:containerView];
    return arrowPointToRect;
}
- (void)_onTouchOverlayViewDidTap:(id)sender{
    [self dismissPopoverAnimated:YES completion:nil];
}
- (BOOL)popoverVisible{
    return self.superview!=nil;
}
+ (MKUIPopoverBorderView *)createBorderView{
    MKUIPopoverBorderView *borderView = [[MKUIPopoverBorderView alloc] init];
    return borderView;
}
- (void)setNeedsReload{
    [self setNeedsLayout];
}
- (void)setContentView:(UIView *)contentView{
    if(_contentView==contentView)return;
    if(_contentView){
        [_contentView removeFromSuperview];
    }
    _contentView = contentView;
    if(_contentView){
        [self addSubview:_contentView];
    }
    [self setNeedsReload];
}
- (void)setContentInsets:(UIEdgeInsets)contentInsets{
    if(UIEdgeInsetsEqualToEdgeInsets(_contentInsets, contentInsets))return;
    _contentInsets = contentInsets;
    [self setNeedsReload];
}
- (void)setPopoverMargins:(UIEdgeInsets)popoverMargins{
    if(UIEdgeInsetsEqualToEdgeInsets(_popoverMargins, popoverMargins))return;
    _popoverMargins = popoverMargins;
    [self setNeedsReload];
}
- (void)setArrowPointToRect:(CGRect)arrowPointToRect{
    if(CGRectEqualToRect(_arrowPointToRect, arrowPointToRect))return;
    _arrowPointToRect = arrowPointToRect;
    [self setNeedsReload];
}
- (void)setArrowSpacing:(CGFloat)arrowSpacing{
    if(_arrowSpacing==arrowSpacing)return;
    _arrowSpacing = arrowSpacing;
    [self setNeedsReload];
}
- (void)setArrowHeight:(CGFloat)arrowHeight{
    if(self.arrowHeight==arrowHeight)return;
    CGSize upArrowSize = self.borderView.upArrowSize;
    upArrowSize.height = arrowHeight;
    self.borderView.upArrowSize = upArrowSize;
    [self setNeedsReload];
}
- (CGFloat)arrowHeight{
    return self.borderView.upArrowSize.height;
}
- (void)setShouldAutoDismiss:(BOOL)shouldAutoDismiss{
    if(_shouldAutoDismiss==shouldAutoDismiss)return;
    _shouldAutoDismiss = shouldAutoDismiss;
    [self _reloadTouchOverlayView];
}
- (void)setPassthroughViews:(NSArray<UIView *> *)passthroughViews{
    self.touchOverlayView.passthroughViews = passthroughViews;
}
- (void)_reloadTouchOverlayView{
    if(self.superview&&self.shouldAutoDismiss){
        [self.superview addSubview:self.touchOverlayView];
        [self.superview bringSubviewToFront:self];
    }else{
        [self.touchOverlayView removeFromSuperview];
    }
}
- (void)didMoveToSuperview{
    [super didMoveToSuperview];
    [self _reloadTouchOverlayView];
}
- (NSArray<UIView *> *)passthroughViews{
    return self.touchOverlayView.passthroughViews;
}
- (void)reloadWithAnimated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion{
    if(!self.superview){
        if(completion){
            completion(NO);
        }
        return;
    }
    if(animated){
        [UIView animateWithDuration:0.2 animations:^{
            [self setNeedsReload];
            [self layoutIfNeeded];
        } completion:^(BOOL finished) {
            if(completion){
                completion(finished);
            }
        }];
    }else{
        [self setNeedsReload];
        [self layoutIfNeeded];
        if(completion){
            completion(YES);
        }
    }
}
- (void)presentPopoverInContainerView:(UIView *)containerView animated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion{
    if(!containerView){
        if(self.superview){
            [self dismissPopoverAnimated:animated completion:completion];
            return;
        }
        if(completion){
            completion(NO);
        }
        return;
    }
    if(animated){
        if(self.superview!=containerView){//先进行移除
            [UIView animateWithDuration:0.1 animations:^{
                self.alpha = 0;
            } completion:^(BOOL finished) {
                [self removeFromSuperview];
                [self _presentPopoverInContainerViewAnimated:containerView duration:0.1 completion:completion];
            }];
        }else{
            [self _presentPopoverInContainerViewAnimated:containerView duration:0.2 completion:completion];
        }
    }else{
        if(self.superview!=containerView){
            if(self.superview){
                [self removeFromSuperview];
            }
        }
        [containerView addSubview:self];
        self.alpha = 1;
        self.transform = CGAffineTransformIdentity;
        [self setNeedsLayout];
        if(self.whenPresented){
            self.whenPresented(self);
        }
        if(completion){
            completion(YES);
        }
    }
}
- (void)_presentPopoverInContainerViewAnimated:(UIView *)containerView duration:(CGFloat)duration completion:(void (^ __nullable)(BOOL finished))completion{
    [containerView addSubview:self];
    [self setNeedsLayout];
    [self layoutIfNeeded];
//    CGRect arrowPointToRect = self.arrowPointToRect;
//    CGPoint arrowPointCenter = MKCGRectGetCenter(arrowPointToRect);
//    CGPoint boundCenter = MKCGRectGetCenter(self.mk_frameSafety);
//    self.alpha = self.alpha==1?0:self.alpha;
//    CGAffineTransform m = CGAffineTransformIdentity;
//    m = CGAffineTransformConcat(m, CGAffineTransformMakeScale(0.1, 0.1));
//    m = CGAffineTransformConcat(m, CGAffineTransformMakeTranslation(arrowPointCenter.x-boundCenter.x, arrowPointCenter.y-boundCenter.y));
//    self.transform = m;
    [UIView animateWithDuration:duration animations:^{
        self.alpha = 1;
//        self.transform = CGAffineTransformIdentity;
    } completion:^(BOOL finished) {
        self.alpha = 1;
//        self.transform = CGAffineTransformIdentity;
        if(self.whenPresented){
            self.whenPresented(self);
        }
        if(completion){
            completion(finished);
        }
    }];
}
- (void)dismissPopoverAnimated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion{
    if(animated){
//        CGRect arrowPointToRect = self.arrowPointToRect;
//        CGPoint arrowPointCenter = MKCGRectGetCenter(arrowPointToRect);
//        CGPoint boundCenter = MKCGRectGetCenter(self.mk_frameSafety);
//        CGAffineTransform m = CGAffineTransformIdentity;
//        m = CGAffineTransformConcat(m, CGAffineTransformMakeScale(0.1, 0.1));
//        m = CGAffineTransformConcat(m, CGAffineTransformMakeTranslation(arrowPointCenter.x-boundCenter.x, arrowPointCenter.y-boundCenter.y));
        [UIView animateWithDuration:0.2 animations:^{
            self.alpha = 0;
//            self.transform = m;
        } completion:^(BOOL finished) {
            [self removeFromSuperview];
            self.alpha = 1;
//            self.transform = CGAffineTransformIdentity;
            if(self.whenDismissed){
                self.whenDismissed(self);
            }
            if(completion){
                completion(finished);
            }
        }];
    }else{
        [self removeFromSuperview];
        if(self.whenDismissed){
            self.whenDismissed(self);
        }
        if(completion){
            completion(YES);
        }
    }
}
- (void)layoutSubviews{
    [super layoutSubviews];
    [self layoutSelfInContainerView];
    CGRect bounds = self.bounds;
    CGRect f1 = UIEdgeInsetsInsetRect(bounds, self.contentInsets);
    CGFloat arrowHeight = self.arrowHeight;
    if(self.popoverArrowDirection==UIPopoverArrowDirectionUp){
        f1.origin.y += arrowHeight;
        f1.size.height -= arrowHeight;
    }else if(self.popoverArrowDirection==UIPopoverArrowDirectionDown){
        f1.size.height -= arrowHeight;
    }else if(self.popoverArrowDirection==UIPopoverArrowDirectionLeft){
        f1.origin.x += arrowHeight;
        f1.size.width -= arrowHeight;
    }else if(self.popoverArrowDirection==UIPopoverArrowDirectionRight){
        f1.size.width -= arrowHeight;
    }
    self.contentView.frame = f1;
    [self.contentView setNeedsLayout];
    [self.contentView layoutIfNeeded];
    //
    self.touchOverlayView.frame = self.superview.bounds;
}
- (UIEdgeInsets)popoverMarginsWithSafeArea{
    UIEdgeInsets insets = self.popoverMargins;
    if (@available(iOS 11.0, *)) {
        UIEdgeInsets safeAreaInsets = (self.superview?:self).safeAreaInsets;
        insets.left += safeAreaInsets.left;
        insets.bottom += safeAreaInsets.bottom;
        insets.right += safeAreaInsets.right;
        insets.top += safeAreaInsets.top;
    }
    return insets;
}
- (CGSize)sizeThatFits:(CGSize)size{
    if(!self.contentView) return CGSizeZero;
    UIEdgeInsets insets = self.contentInsets;
    CGSize limitSize = CGSizeMake(size.width-MKUIEdgeInsetsGetEdgeSum(insets, MKCGAxisX), size.height-MKUIEdgeInsetsGetEdgeSum(insets, MKCGAxisY));
    if(limitSize.width<=0||limitSize.height<=0) return CGSizeZero;
    
    CGSize s = [self contentViewSizeThatFits:limitSize];
    if(!CGSizeEqualToSize(s, CGSizeZero)){
        s.width += MKUIEdgeInsetsGetEdgeSum(insets, MKCGAxisX);
        s.height += MKUIEdgeInsetsGetEdgeSum(insets, MKCGAxisY);
    }
    return s;
}
- (CGSize)contentViewSizeThatFits:(CGSize)size{
    CGSize s = [self.contentView sizeThatFits:size];
    return s;
}
- (void)layoutSelfInContainerView{
    CGRect bounds = self.superview.bounds;//外层容器尺寸
    UIEdgeInsets popoverMargins = self.popoverMarginsWithSafeArea;
    bounds = UIEdgeInsetsInsetRect(bounds, popoverMargins);
    CGRect arrowPointToRect = self.arrowPointToRect;//箭头指定的目标区域
    CGFloat arrowHeight = self.arrowHeight;
    //计算合适的箭头方向
    _MKUIPopoverViewDirectionAreaInfo *directionInfo = [self directionInfoThatFit:self.permittedArrowDirections];
    CGSize limitSize = directionInfo.rect.size;
    MKCGAxis Y = directionInfo.directionAxis;
    MKCGAxis X = MKCGAxisReverse(Y);
    MKCGSizeAddLength(&limitSize, Y, -arrowHeight);//扣除箭头的高度值
    
    CGSize size = [self sizeThatFits:limitSize];
    
    //判断size值是否超出当前可用区域
    if((MKCGSizeGetLength(size, Y))>ceil(MKCGSizeGetLength(limitSize, Y))
       ||(MKCGSizeGetLength(size, X))>ceil(MKCGSizeGetLength(limitSize, X))
       ){
        //当前箭头方向不足以容纳内容视图，尝试换其他方向
        if(self.permittedArrowDirections!=UIPopoverArrowDirectionAny){
            _MKUIPopoverViewDirectionAreaInfo *tryDirectionInfo = [self directionInfoThatFit:UIPopoverArrowDirectionAny];//尝试最大可用空间的方向
            limitSize = tryDirectionInfo.rect.size;
            Y = tryDirectionInfo.directionAxis;
            X = MKCGAxisReverse(Y);
            MKCGSizeAddLength(&limitSize, Y, -arrowHeight);//扣除箭头的高度值
            size = [self sizeThatFits:limitSize];
            directionInfo = tryDirectionInfo;
        }
    }
    
    if(!CGSizeEqualToSize(size, CGSizeZero)){
        MKCGSizeAddLength(&size, Y, arrowHeight);//添加箭头的高度值
    }
    
    self.popoverArrowDirection = directionInfo.direction;
    CGRect f1 = directionInfo.rect;
    f1.size = size;
    MKCGRectAlignMidToRect(&f1, X, arrowPointToRect);
    MKCGRectSetMin(&f1, X, MAX(MKCGRectGetMin(f1, X),MKCGRectGetMin(bounds,X)));
    MKCGRectSetMax(&f1, X, MIN(MKCGRectGetMax(f1, X),MKCGRectGetMax(bounds,X)));
    if(self.popoverArrowDirection==UIPopoverArrowDirectionDown
       ||self.popoverArrowDirection==UIPopoverArrowDirectionRight
       ){
        MKCGRectAlignMaxToRect(&f1, Y, directionInfo.rect);
    }
    self.mk_frameSafety = f1;
    //
    CGSize arrowSize = self.borderView.upArrowSize;
    arrowSize.height = self.arrowHeight;
    self.borderView.upArrowSize = arrowSize;
    self.borderView.arrowDirection = self.popoverArrowDirection;
    self.borderView.arrowPoint = MKCGRectGetCenter([self.superview convertRect:self.arrowPointToRect toView:self.borderView]);
    CGRect f2 = self.bounds;
    self.borderView.frame = f2;
}
- (_MKUIPopoverViewDirectionAreaInfo *)directionInfoThatFit:(UIPopoverArrowDirection)permittedArrowDirections{
    CGRect bounds = self.superview.bounds;//外层容器尺寸
    UIEdgeInsets popoverMargins = self.popoverMarginsWithSafeArea;
    bounds = UIEdgeInsetsInsetRect(bounds, popoverMargins);
    CGRect arrowPointToRect = self.arrowPointToRect;//箭头指定的目标区域
    CGFloat arrowSpacing = self.arrowSpacing;//与箭头指向的目标区域的间隔
    CGFloat cornerRadius = self.borderView.cornerRadius;
    UIEdgeInsets contentInsets = self.contentInsets;
    CGFloat arrowHeight = self.arrowHeight;
    //计算合适的箭头方向
    NSMutableArray *items = [[NSMutableArray alloc] initWithCapacity:4];
    {//up
        MKCGAxis Y = MKCGAxisY;
        CGRect contentRect = bounds;
        MKCGRectSetMin(&contentRect, Y, MKCGRectGetMax(arrowPointToRect, Y)+arrowSpacing);
        MKCGRectSetLength(&contentRect, Y, MKCGRectGetMax(bounds, Y)-MKCGRectGetMin(contentRect, Y));
        [items addObject:[[_MKUIPopoverViewDirectionAreaInfo alloc] initWithDirection:UIPopoverArrowDirectionUp rect:contentRect]];
    }
    {//down
        MKCGAxis Y = MKCGAxisY;
        CGRect contentRect = bounds;
        MKCGRectSetMin(&contentRect, Y, MKCGRectGetMin(bounds, Y));
        MKCGRectSetLength(&contentRect, MKCGAxisY, MKCGRectGetMin(arrowPointToRect, Y)-arrowSpacing-MKCGRectGetMin(contentRect, Y));
        [items addObject:[[_MKUIPopoverViewDirectionAreaInfo alloc] initWithDirection:UIPopoverArrowDirectionDown rect:contentRect]];
    }
    {//left
        MKCGAxis Y = MKCGAxisX;
        CGRect contentRect = bounds;
        MKCGRectSetMin(&contentRect, Y, MKCGRectGetMax(arrowPointToRect, Y)+arrowSpacing);
        MKCGRectSetLength(&contentRect, Y, MKCGRectGetMax(bounds, MKCGAxisX)-MKCGRectGetMin(contentRect, Y));
        [items addObject:[[_MKUIPopoverViewDirectionAreaInfo alloc] initWithDirection:UIPopoverArrowDirectionLeft rect:contentRect]];
    }
    {//right
        MKCGAxis Y = MKCGAxisX;
        CGRect contentRect = bounds;
        MKCGRectSetMin(&contentRect, Y, MKCGRectGetMin(bounds, Y));
        MKCGRectSetLength(&contentRect, MKCGAxisX, MKCGRectGetMin(arrowPointToRect, Y)-arrowSpacing-MKCGRectGetMin(contentRect, Y));
        [items addObject:[[_MKUIPopoverViewDirectionAreaInfo alloc] initWithDirection:UIPopoverArrowDirectionRight rect:contentRect]];
    }
    NSArray *sortedItems = [items sortedArrayUsingComparator:^NSComparisonResult(_MKUIPopoverViewDirectionAreaInfo * _Nonnull obj1, _MKUIPopoverViewDirectionAreaInfo * _Nonnull obj2) {
        return -1*[obj1 compare:obj2];
    }];
    
    NSArray<_MKUIPopoverViewDirectionAreaInfo *> *filerItems = self.permittedArrowDirections==UIPopoverArrowDirectionUnknown?sortedItems:[sortedItems mk_map:^id _Nullable(_MKUIPopoverViewDirectionAreaInfo * _Nonnull obj) {
        if((obj.direction&permittedArrowDirections) ==0) return nil;//不在期望的方向中
        if(obj.area<0) return nil;//可用面积为负
        CGFloat h = MKCGRectGetLength(obj.rect, obj.directionAxis);
        CGFloat minHeightDirection = arrowHeight+MAX(MKUIEdgeInsetsGetEdgeSum(contentInsets, obj.directionAxis),2*cornerRadius);
        if(h<minHeightDirection) return nil;//可用的高度值不够
        return obj;
    }];
    _MKUIPopoverViewDirectionAreaInfo *directionInfo = filerItems.count>0?filerItems.firstObject:sortedItems.firstObject;
    return directionInfo;
}
@end

#import "UIColor+MKUI.h"
#import "CGGeometry+MKUI.h"
@interface MKUIPopoverBorderView()

@property(nonatomic,strong) UIBezierPath *borderPath;
@end
@implementation MKUIPopoverBorderView
- (id)init{
    if(self=[super init]){
        self.clipsToBounds = NO;
        self.backgroundColor = UIColor.clearColor;
        self.upArrowSize = CGSizeMake(9, 7);
        self.cornerRadius = 7;
        self.borderColor = [UIColor mk_popoverBorderColor];
        self.fillColor = [UIColor mk_popoverBorderColor];
        self.lineWidth = 1;
        self.layer.shadowColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:0.5].CGColor;
        self.layer.shadowOffset = CGSizeMake(0, 2);
        self.layer.shadowOpacity = 0.5;
        self.layer.shadowRadius = 2.0;
    }
    return self;
}
- (void)_setNeedsDisplayBorder{
    self.borderPath = nil;
    [self setNeedsDisplay];
}
- (void)setUpArrowSize:(CGSize)upArrowSize{
    if(CGSizeEqualToSize(_upArrowSize, upArrowSize))return;
    _upArrowSize = upArrowSize;
    [self _setNeedsDisplayBorder];
}
- (void)setCornerRadius:(CGFloat)cornerRadius{
    if(_cornerRadius==cornerRadius)return;
    _cornerRadius = cornerRadius;
    [self _setNeedsDisplayBorder];
}
- (void)setBorderColor:(UIColor *)borderColor{
    if(borderColor==_borderColor||[borderColor isEqual:_borderColor])return;
    _borderColor = borderColor;
    [self _setNeedsDisplayBorder];
}
- (void)setFillColor:(UIColor *)fillColor{
    if(fillColor==_fillColor||[fillColor isEqual:_fillColor])return;
    _fillColor = fillColor;
    [self _setNeedsDisplayBorder];
}
- (void)setArrowPoint:(CGPoint)arrowPoint{
    if(CGPointEqualToPoint(arrowPoint, _arrowPoint)) return;
    _arrowPoint = arrowPoint;
    [self _setNeedsDisplayBorder];
}
- (void)setArrowDirection:(UIPopoverArrowDirection)arrowDirection{
    if(_arrowDirection==arrowDirection)return;
    _arrowDirection = arrowDirection;
    [self _setNeedsDisplayBorder];
}
- (void)setLineWidth:(CGFloat)lineWidth{
    if(_lineWidth==lineWidth)return;
    _lineWidth = lineWidth;
    [self _setNeedsDisplayBorder];
}
- (void)drawRect:(CGRect)rect{
    [super drawRect:rect];
    [self drawArrowBorder:rect];
}
- (void)drawArrowBorder:(CGRect)rect{
    self.borderPath = [self createBorderPath];
    if(self.borderColor){
        [self.borderColor setStroke];
        [self.borderPath stroke];
    }
    if(self.fillColor){
        [self.fillColor setFill];
        [self.borderPath fill];
    }
}
- (CGSize)sizeThatFits:(CGSize)size{
    UIBezierPath *path = [self createBorderPath];
    CGRect rect = path.bounds;
    CGSize s = rect.size;
    return s;
}
- (UIBezierPath *)createBorderPath{
    CGFloat lineWidth = self.lineWidth;
    CGRect bounds = self.bounds;
    CGPoint arrowPoint = self.arrowPoint;
    CGSize upArrowSize = self.upArrowSize;
    CGFloat cornerRadius = self.cornerRadius;
    
    MKArrowUIBezierPath *pathObject = [[MKArrowUIBezierPath alloc] init];
    pathObject.lineWidth = lineWidth;
    pathObject.bounds = bounds;
    pathObject.arrowDirection = self.arrowDirection;
    pathObject.upArrowSize = upArrowSize;
    pathObject.cornerRadius = cornerRadius;
    pathObject.arrowPoint = arrowPoint;
    UIBezierPath *borderPath = [pathObject createArrowPath];
    
    return borderPath;
}
@end
@implementation MKArrowUIBezierPath
/// 绘制带箭头的圆角矩形图形
/**
 
  *
__________
__/\_
|         |
|____|
*/
/// - Parameters:
///   - bounds: 圆角矩形+箭头区域合并起来的frame
///   - arrowPoint: 箭头指定坐标
///   - arrowSize: 箭头的尺寸
///   - cornerRadius: 圆角半径
+ (UIBezierPath *)arrowPathWithBounds:(CGRect)containerBounds contentInsets:(UIEdgeInsets)contentInsets arrowPoint:(CGPoint)arrowPoint arrowSize:(CGSize)arrowSize cornerRadius:(CGFloat)cornerRadius lineWidth:(CGFloat)lineWidth{
    CGRect bounds = UIEdgeInsetsInsetRect(containerBounds, contentInsets);
    cornerRadius = MIN(cornerRadius,bounds.size.width/2);
    cornerRadius = MIN(cornerRadius,bounds.size.height/2);
    
    UIBezierPath *borderPath = [UIBezierPath bezierPath];
    borderPath.lineWidth = lineWidth;
    borderPath.lineCapStyle = kCGLineCapRound;//线条拐角
    borderPath.lineJoinStyle = kCGLineJoinRound;//终点处理
    CGFloat bodyX = MKCGRectGetMin(bounds, MKCGAxisX);
    CGFloat bodyX_max = MKCGRectGetMax(bounds, MKCGAxisX);
    CGFloat arrowPointX = MKCGPointGetValue(arrowPoint, MKCGAxisX);
    arrowPointX = MIN(arrowPointX,MKCGRectGetMax(containerBounds, MKCGAxisX));
    arrowPointX = MAX(arrowPointX,MKCGRectGetMin(containerBounds, MKCGAxisX));
    [borderPath moveToPoint:CGPointMake(arrowPointX, MKCGRectGetMin(bounds, MKCGAxisY))];//箭头尖头
    CGFloat arrowBaseWidth = MKCGSizeGetLength(arrowSize, MKCGAxisX);
    CGFloat arrowBaseHeight = MKCGSizeGetLength(arrowSize, MKCGAxisY);
    CGFloat arrowBaseX_1 = arrowPointX+arrowBaseWidth/2;
    CGFloat arrowBaseY = MKCGRectGetMin(bounds, MKCGAxisY)+arrowBaseHeight;
    
    arrowBaseX_1 = MAX(arrowBaseX_1,bodyX+arrowBaseWidth);//
    arrowBaseX_1 = MIN(arrowBaseX_1,bodyX_max);//不能超过body右侧
    [borderPath addLineToPoint:CGPointMake(arrowBaseX_1, arrowBaseY)];//绘制箭头右边
    if(arrowBaseX_1<bodyX_max-cornerRadius){
        [borderPath addLineToPoint:CGPointMake(bodyX_max-cornerRadius, arrowBaseY)];//绘制箭头右端到body右侧的直线
    }
    
    CGFloat cornerRadiusTopRight = MIN(bodyX_max-arrowBaseX_1,cornerRadius);
    if(cornerRadiusTopRight>0){
        [borderPath addArcWithCenter:CGPointMake(bodyX_max-cornerRadiusTopRight, arrowBaseY+cornerRadiusTopRight) radius:cornerRadiusTopRight startAngle:-M_PI_2 endAngle:0 clockwise:YES];//绘制右上角圆弧
    }
    CGFloat bodyY_bottom = MKCGRectGetMax(bounds, MKCGAxisY);
    CGFloat bodyY_bottomRight0 = bodyY_bottom-cornerRadius;
    if(bodyY_bottomRight0>0){
        [borderPath addLineToPoint:CGPointMake(bodyX_max, bodyY_bottomRight0)];//绘制body的右侧直线
    }
    if(cornerRadius>0){
        [borderPath addArcWithCenter:CGPointMake(bodyX_max-cornerRadius, bodyY_bottomRight0) radius:cornerRadius startAngle:0 endAngle:M_PI_2 clockwise:YES];//绘制右下角圆弧
    }
    
    CGFloat bodyY_max = MKCGRectGetMax(bounds, MKCGAxisY);
    CGFloat bodyX_bottomLeft0 = bodyX+cornerRadius;
    if(bodyX_max-cornerRadius>bodyX_bottomLeft0){
        [borderPath addLineToPoint:CGPointMake(bodyX_bottomLeft0, bodyY_max)];//绘制body下方直线
    }
    if(cornerRadius>0){
        [borderPath addArcWithCenter:CGPointMake(bodyX_bottomLeft0, bodyY_max-cornerRadius) radius:cornerRadius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];//绘制左下角圆弧
    }
    CGFloat arrowBaseX_0 = arrowPointX-arrowBaseWidth/2;
    arrowBaseX_0 = MAX(arrowBaseX_0,bodyX);
    arrowBaseX_0 = MIN(arrowBaseX_0,bodyX_max-arrowBaseWidth);
    CGFloat cornerRadiusTopLeft = MIN(arrowBaseX_0-bodyX,cornerRadius);//左上角圆弧半径
    CGFloat bodyY = MKCGRectGetMin(bounds, MKCGAxisY)+arrowBaseHeight;
    CGFloat bodyY_topLeft0 = bodyY+cornerRadiusTopLeft;
    CGFloat bodyY_topBottom0 = bodyY_max-cornerRadius;
    if(bodyY_topBottom0>bodyY_topLeft0){
        [borderPath addLineToPoint:CGPointMake(bodyX, bodyY_topLeft0)];//绘制左侧直线
    }
    if(cornerRadiusTopLeft>0){
        [borderPath addArcWithCenter:CGPointMake(bodyX+cornerRadiusTopLeft, bodyY_topLeft0) radius:cornerRadiusTopLeft startAngle:M_PI endAngle:M_PI+M_PI_2 clockwise:YES];//绘制左上角圆弧
    }
    CGFloat bodyX_topLeft0 = bodyX+cornerRadiusTopLeft;
    if(arrowBaseX_0>bodyX_topLeft0){
        [borderPath addLineToPoint:CGPointMake(arrowBaseX_0, arrowBaseY)];//绘制左上角连接箭头左端点
    }
    [borderPath closePath];
    return borderPath;
}
- (UIBezierPath *)createArrowPath{
    CGFloat lineWidth = self.lineWidth;
    UIEdgeInsets contentInsets = MKUIEdgeInsetsMakeSameEdge(lineWidth);
    
    CGRect bounds = self.bounds;
    CGPoint arrowPoint = self.arrowPoint;
    CGSize arrowSize = self.upArrowSize;
    CGFloat cornerRadius = self.cornerRadius;
    
    CGAffineTransform m = CGAffineTransformIdentity;
    CGAffineTransform m_r = CGAffineTransformIdentity;
    if(self.arrowDirection==UIPopoverArrowDirectionUp){
/**
__/\_
|         |
|____|
*/
    }else if(self.arrowDirection==UIPopoverArrowDirectionDown){
/**
_____
|         |
|__  _|
  V
*/
        m = CGAffineTransformConcat(m, CGAffineTransformMakeTranslation(0, -MKCGRectGetMid(bounds, MKCGAxisY)));
        m = CGAffineTransformConcat(m, CGAffineTransformMakeScale(1, -1));
        m = CGAffineTransformConcat(m, CGAffineTransformMakeTranslation(0, MKCGRectGetMid(bounds, MKCGAxisY)));
        bounds = CGRectApplyAffineTransform(bounds, m);
        arrowPoint = CGPointApplyAffineTransform(arrowPoint, m);
        m_r = CGAffineTransformInvert(m);
    }else if(self.arrowDirection==UIPopoverArrowDirectionLeft){
/**
 _____
 |          |
<     |
 |__ __|
*/
        m = CGAffineTransformConcat(m, CGAffineTransformMakeTranslation(-MKCGRectGetMid(bounds, MKCGAxisX), -MKCGRectGetMid(bounds, MKCGAxisY)));
        m = CGAffineTransformConcat(m, CGAffineTransformMakeRotation(M_PI_2));
        m = CGAffineTransformConcat(m, CGAffineTransformMakeTranslation(MKCGRectGetMid(bounds, MKCGAxisX), MKCGRectGetMid(bounds, MKCGAxisY)));
        bounds = CGRectApplyAffineTransform(bounds, m);
        arrowPoint = CGPointApplyAffineTransform(arrowPoint, m);
        m_r = CGAffineTransformInvert(m);
    }else if(self.arrowDirection==UIPopoverArrowDirectionRight){
/**
 _____
 |          |
 |          >
 |__ __|
*/
        
        m = CGAffineTransformConcat(m, CGAffineTransformMakeTranslation(-MKCGRectGetMid(bounds, MKCGAxisX), -MKCGRectGetMid(bounds, MKCGAxisY)));
        m = CGAffineTransformConcat(m, CGAffineTransformMakeRotation(-M_PI_2));
        m = CGAffineTransformConcat(m, CGAffineTransformMakeTranslation(MKCGRectGetMid(bounds, MKCGAxisX), MKCGRectGetMid(bounds, MKCGAxisY)));
        bounds = CGRectApplyAffineTransform(bounds, m);
        arrowPoint = CGPointApplyAffineTransform(arrowPoint, m);
        m_r = CGAffineTransformInvert(m);
    }
    UIBezierPath *borderPath = [self.class arrowPathWithBounds:bounds contentInsets:contentInsets arrowPoint:arrowPoint arrowSize:arrowSize cornerRadius:cornerRadius lineWidth:lineWidth];
    [borderPath applyTransform:m_r];
    return borderPath;
}
@end

#import "UIView+MKUI.h"
@implementation MKUIPopoverView(UIView)
- (void)presentPopoverInWindowPointToView:(UIView *)view animated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion{
    UIView *containerView = [view mk_firstSuperViewWithClass:UIWindow.class];
    [self presentPopoverPointToView:view inContainerView:containerView animated:animated completion:completion];
}
- (void)presentPopoverPointToView:(UIView *)view inContainerView:(UIView *)containerView animated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion{
    CGRect arrowPointToRect = [MKUIPopoverView arrowPointToRectFrom:view inContainerView:containerView];
    self.arrowPointToRect = arrowPointToRect;
    [self presentPopoverInContainerView:containerView animated:animated completion:completion];
}
@end
@implementation UIView(MKUIPopoverView)
- (void)mk_dismissSubViewPopoverAnimated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion{
    MKUIPopoverView *popView = nil;
    for(UIView *s in self.subviews){
        if([s isKindOfClass:MKUIPopoverView.class]){
            popView = (MKUIPopoverView *)s;
            break;
        }
    }
    if(!popView){
        if(completion){
            completion(NO);
        }
        return;
    }
    [popView dismissPopoverAnimated:animated completion:completion];
}
- (void)mk_dismissUIWindowPopoverAnimated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion{
    UIWindow *window = [self mk_firstSuperViewWithClass:UIWindow.class];
    if(!window){
        if(completion){
            completion(NO);
        }
        return;
    }
    [window mk_dismissSubViewPopoverAnimated:animated completion:completion];
}
@end
